package com.learning.jquizenglish.network.connection;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.net.URLConnection;
import java.util.List;
import java.util.concurrent.TimeoutException;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion;
import org.apache.http.NameValuePair;
import org.apache.http.ParseException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.params.ConnManagerPNames;
import org.apache.http.conn.params.ConnPerRouteBean;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.util.EntityUtils;

import android.net.http.AndroidHttpClient;
import android.util.Log;

public final class HttpUtil {

    // ===================================================================
    // Constants
    // ===================================================================
    private static final String LOG_TAG = HttpUtil.class.getSimpleName();

    private static final String USER_AGENT = null;
    public static final int TIME_OUT_CONNECTION = 15000;// 15s
    public static final int TIME_OUT_SOCKET = 15000;// 15s

    // ===================================================================
    // Fields
    // ===================================================================

    // ===================================================================
    // Constructors
    // ===================================================================

    // ===================================================================
    // Getter & Setter
    // ===================================================================
    public static String getStringResponeByPostMethod(String pUrl, List<NameValuePair> pNameValuePairs,
            final File pBuffer) throws IOException {
        return HttpUtil.excuteByPostMethod(pUrl, pNameValuePairs, pBuffer);
    }

    public static String getStringResponeByPostMethod(String pUrl, List<NameValuePair> pNameValuePairs)
            throws IOException {
        return HttpUtil.excuteByPostMethod(pUrl, pNameValuePairs, null);
    }

    public static String getStringResponseByGetMethod(String pUrl, final File pBuffer) throws IOException {
        return HttpUtil.excuteByGetMethod(pUrl, pBuffer);
    }

    public static String getStringResponseByGetMethod(String pUrl) throws IOException {
        return HttpUtil.excuteByGetMethod(pUrl, null);
    }

    private static String executeRequest(HttpUriRequest pHttpUriRequest, final File pBuffer)
            throws IOException {
        String returnString = "";
        HttpResponse response = null;
        AndroidHttpClient client = getAndroidHttpClient(pHttpUriRequest);
        try {
            response = client.execute(pHttpUriRequest);
            final int statusCode = response.getStatusLine().getStatusCode();
            if (statusCode == HttpStatus.SC_OK) {
                HttpEntity getResponseEntity = response.getEntity();
                if (getResponseEntity != null) {
                    if (pBuffer == null) {
                        if (getResponseEntity.getContentEncoding() != null
                                && getResponseEntity.getContentEncoding().getValue().equalsIgnoreCase("gzip")) {
                            InputStream inputStream =
                                    AndroidHttpClient.getUngzippedContent(getResponseEntity);
                            getResponseEntity = null;
                            response = null;
                            System.gc();
                            System.gc();
                            returnString = IOUtil.inputStreamToString(inputStream);
                        } else {
                            returnString = EntityUtils.toString(getResponseEntity, "UTF-8");
                        }
                    } else {
                        returnString = writeResponseToFile(pBuffer, getResponseEntity);
                    }
                } else {
                    Log.e(LOG_TAG, "Response Entity is null !");
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
            pHttpUriRequest.abort();
            client.close();
            if (AndroidVersionUtils.isBeforeGingerbread()) {
                if (e instanceof SocketTimeoutException) {
                    throw new SocketTimeoutException("SocketTimeoutException");
                } else if (e instanceof ConnectTimeoutException) {
                    throw new ConnectTimeoutException("ConnectTimeoutException");
                } else {
                    throw e;
                }
            } else {
                if (e instanceof SocketTimeoutException) {
                    throw new SocketTimeoutException("SocketTimeoutException");
                } else if (e instanceof ConnectTimeoutException) {
                    throw new ConnectTimeoutException("ConnectTimeoutException");
                } else {
                    throw e;
                }
            }
        } catch (OutOfMemoryError e) {
            System.gc();
            System.gc();
        } finally {
            client.close();
            response = null;
            client = null;
            System.gc();
            System.gc();
        }
        return returnString;
    }


    public static String getStringByGetMethod(String pUrl) throws ParseException, IOException {
        String returnString = "";
        DefaultHttpClient client = new DefaultHttpClient();
        HttpConnectionParams.setConnectionTimeout(client.getParams(), TIME_OUT_CONNECTION);
        HttpConnectionParams.setSoTimeout(client.getParams(), TIME_OUT_SOCKET);
        HttpGet getRequest = new HttpGet(pUrl);
        getRequest.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
        getRequest.setHeader("Pragma", "no-cache");
        getRequest.setHeader("Expires", "0");
        try {
            HttpResponse getResponse = client.execute(getRequest);
            final int statusCode = getResponse.getStatusLine().getStatusCode();
            if (statusCode != HttpStatus.SC_OK) {
                returnString = "";
            } else {
                HttpEntity getResponseEntity = getResponse.getEntity();
                if (statusCode != HttpStatus.SC_NO_CONTENT && getResponseEntity != null) {
                    returnString = EntityUtils.toString(getResponseEntity);
                }
            }
        } catch (IOException e) {
            getRequest.abort();
            client.getConnectionManager().shutdown();
            if (AndroidVersionUtils.isBeforeGingerbread()) {
                throw new IOException();
            } else {
                throw new IOException(e);
            }
        } finally {
            client.getConnectionManager().shutdown();
        }
        return returnString;
    }

    // ===================================================================
    // Methods from BaseClass & Interfaces
    // ===================================================================

    // ===================================================================
    // Methods
    // ===================================================================
    private static String excuteByPostMethod(String pUrl, List<NameValuePair> pNameValuePairs,
            final File pBuffer) throws IOException {
        HttpPost httpPost = new HttpPost(pUrl);
        httpPost.setEntity(new UrlEncodedFormEntity(pNameValuePairs, "UTF-8"));
        return executeRequest(httpPost, pBuffer);
    }

    private static String excuteByGetMethod(String pUrl, final File pBuffer) throws IOException {
        HttpGet httpGet = new HttpGet(pUrl);
        return executeRequest(httpGet, pBuffer);
    }

    public static AndroidHttpClient getAndroidHttpClient(HttpUriRequest request) {
        AndroidHttpClient client = AndroidHttpClient.newInstance(USER_AGENT);
        client.getParams().setParameter("http.protocol.content-charset", "UTF-8");
        HttpConnectionParams.setConnectionTimeout(client.getParams(), TIME_OUT_CONNECTION);
        HttpConnectionParams.setSoTimeout(client.getParams(), TIME_OUT_SOCKET);
        request.setHeader("Content-Type", "application/x-www-form-urlencoded");
        request.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
        request.setHeader("Pragma", "no-cache");
        request.setHeader("Expires", "0");
        request.setParams(client.getParams());
        return client;
    }

    // private static String executeRequest(HttpUriRequest pHttpUriRequest, final File pBuffer)
    // throws IOException {
    // String returnString = "";
    // HttpResponse response = null;
    // AndroidHttpClient client = getAndroidHttpClient(pHttpUriRequest);
    // try {
    // response = client.execute(pHttpUriRequest);
    // HttpEntity getResponseEntity = response.getEntity();
    // if (pBuffer == null) {
    // returnString = EntityUtils.toString(getResponseEntity);
    // } else {
    // returnString = writeResponseToFile(pBuffer, getResponseEntity);
    // }
    // } catch (IOException e) {
    // e.printStackTrace();
    // pHttpUriRequest.abort();
    // client.close();
    // if (AndroidVersionUtils.isBeforeGingerbread()) {
    // throw new IOException();
    // } else {
    // throw new IOException(e);
    // }
    // } finally {
    // client.close();
    // response = null;
    // client = null;
    // }
    // return returnString;
    // }

    /**
     * Executes {@link HttpUriRequest}
     * 
     * @param httpUriRequest {@link HttpUriRequest}
     * @return Response in format of string
     * @throws IOException
     * @throws ClientProtocolException
     */
    // public String executeRequest(HttpUriRequest httpUriRequest) throws ClientProtocolException,
    // IOException {
    // String responseInputStream = null;
    // DefaultHttpClient defaultHttpClient = null;
    // HttpResponse httpResponse = null;
    //
    // try {
    // // -- Create Http Client --//
    // defaultHttpClient = createHttpClient();
    //
    // // -- Execute the request --//
    // httpResponse = defaultHttpClient.execute(httpUriRequest);
    // final int statusCode = httpResponse.getStatusLine().getStatusCode();
    // // -- Get the response --//
    // if (statusCode != HttpStatus.SC_NO_CONTENT && statusCode == HttpStatus.SC_OK) {
    // responseInputStream = getHttpResponseStream(httpResponse);
    // }
    // // else
    // // // -- Parse error response --//
    // // if (statusCode != HttpStatus.SC_OK && statusCode != HttpStatus.SC_CREATED
    // // && statusCode != HttpStatus.SC_NO_CONTENT) {
    // // String errorCode = null;
    // // String errorMessage = null;
    // // if (errorMessage == null) {
    // // errorCode = "" + statusCode;
    // // errorMessage = httpResponse.getStatusLine().getReasonPhrase();
    // // }
    // // }
    // } finally {
    // defaultHttpClient.getConnectionManager().shutdown();
    // defaultHttpClient = null;
    // httpResponse = null;
    // }
    // // -- Return The Response --//
    // return responseInputStream;
    // }

    /**
     * Creates a new HTTP client and a connection manager.
     * 
     * @return HttpClient Returns new HttpClient if there is no error.
     * @throws MobiBookException All error will be thrown as {@link MobiBookException} to the caller
     *         function.
     */
    public static DefaultHttpClient createHttpClient() {
        SchemeRegistry schemeRegistry = new SchemeRegistry();
        schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
        schemeRegistry.register(new Scheme("https", NoTrustSSLSocketFactory.getFactory(), 443));

        HttpParams params = new BasicHttpParams();
        params.setParameter(ConnManagerPNames.MAX_TOTAL_CONNECTIONS, 30);
        params.setParameter(ConnManagerPNames.MAX_CONNECTIONS_PER_ROUTE, new ConnPerRouteBean(30));
        params.setParameter(ConnManagerPNames.TIMEOUT, 30000L);
        params.setParameter(HttpProtocolParams.USE_EXPECT_CONTINUE, false);

        HttpConnectionParams.setSoTimeout(params, 50000);
        HttpConnectionParams.setConnectionTimeout(params, 50000);
        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
        ClientConnectionManager cm = new ThreadSafeClientConnManager(params, schemeRegistry);
        return new DefaultHttpClient(cm, params);
    }

    /**
     * Method to convert HTTP response as {@link InputStream} and then {@link String} output.
     * 
     * @return HTTP Response in {@link String} format, obtained from {@link HttpResponse}
     * @throws IOException
     */
    public static String getHttpResponseStream(HttpResponse httpResponse) throws IOException {

        InputStream responseInputStream = null;
        responseInputStream = httpResponse.getEntity().getContent();
        StringBuilder sb = new StringBuilder();
        BufferedReader reader = new BufferedReader(new InputStreamReader(responseInputStream));

        String line = null;

        while ((line = reader.readLine()) != null) {
            sb.append(line + "\n");
        }

        responseInputStream.close();
        return sb.toString();
    }

    private static String writeResponseToFile(File pBuffer, HttpEntity pEntity) throws IOException {
        FileOutputStream output = new FileOutputStream(pBuffer);
        pEntity.writeTo(output);
        output.close();
        return IOUtil.fileToString(pBuffer);
    }

    public static InputStream getStreamFromNetwork(final String pUrl) {
        // cach 1
        // HttpGet httpRequest = new HttpGet(pUrl);
        // AndroidHttpClient httpClient = getAndroidHttpClient(httpRequest);
        InputStream is = null;
        try {
            // HttpResponse response = httpClient.execute(httpRequest);
            // HttpEntity entity = response.getEntity();
            // if (entity == null || entity.getContentLength() == -1
            // || entity.getContentLength() > 5 * 1024 * 1024) {// 5MB
            // Log.e(LOG_TAG,
            // "Size too big aborted download file ! file size : " + entity.getContentLength());
            // return null;
            // }
            // BufferedHttpEntity bufHttpEntity = new BufferedHttpEntity(entity);
            // is = bufHttpEntity.getContent();
            // cach 2
            URL url = new URL(pUrl);
            URLConnection conexion = url.openConnection();
            conexion.setConnectTimeout(TIME_OUT_CONNECTION);
            conexion.setReadTimeout(TIME_OUT_SOCKET);
            conexion.connect();
            int lenghtOfFile = conexion.getContentLength();
            Log.v(LOG_TAG, "lenghtOfFile = " + lenghtOfFile);
            is = url.openStream();
        } catch (Exception e) {} finally {
            // httpRequest = null;
            // httpClient.close();
            // httpClient = null;
        }
        return is;
    }
    
    public static String getStringRespondFromSoap(String url,String requestContent) {
        try {
                URL u = new URL(url);
                URLConnection uc = u.openConnection();
                HttpURLConnection connection = (HttpURLConnection) uc;
                connection.setUseCaches(false);
                connection.setRequestProperty("Connection", "keep-alive");
                connection.setDoOutput(true);
                connection.setDoInput(true);
                connection.setConnectTimeout(30000);
                connection.setRequestMethod("POST");
                connection.setRequestProperty("soapAction", "");
                connection.setRequestProperty("Content-Type",
                                "text/xml;charset=UTF-8");
                int len = requestContent.length();
                connection.setRequestProperty("Content-Length",
                                Integer.toString(len));
                connection.connect();
                OutputStream out = connection.getOutputStream();
                OutputStreamWriter wout = new OutputStreamWriter(out);
                wout.write(requestContent);
                wout.flush();
                wout.close();

                StringBuffer response = new StringBuffer();
                InputStream inStream = connection.getInputStream();
                BufferedReader rd = new BufferedReader(new InputStreamReader(
                                inStream));
                String line;
                while ((line = rd.readLine()) != null) {
                        response.append(line);
                        String sReturn = response.toString();
                        return sReturn;
                }
        } catch (IOException e) {
        	e.printStackTrace();
                return "";
        }
        return "";

}
    public static HttpClient getDefaultHttpClient() {
        HttpParams params = new BasicHttpParams();
        HttpConnectionParams.setConnectionTimeout(params, TIME_OUT_CONNECTION);
        HttpConnectionParams.setSoTimeout(params, TIME_OUT_SOCKET);
        HttpClient client = new DefaultHttpClient(params);
        return client;
    }
    
    public static String executeHttpRequest(HttpRequestBase request)throws SocketException,TimeoutException,IOException {
        String ret = null;
        HttpClient client = getDefaultHttpClient();
        ResponseHandler<String> handler = new BasicResponseHandler();
        try {
            ret = client.execute(request, handler);
        }
        catch(Exception ex){
            ex.printStackTrace();
               if(ex instanceof SocketException){
                   throw new SocketException();
               } else if(ex instanceof TimeoutException || ex instanceof ConnectTimeoutException || ex instanceof SocketTimeoutException){
                   throw new TimeoutException();
               } else throw new IOException();
            }
        return ret;
    }
    
    
    public static String getStringResponeByPostMultipart(String url,MultipartEntity reqEntity){
    	if(reqEntity == null) return null;
    	String ret = null;
    	try {
        	HttpPost httpPost = new HttpPost(url);
            httpPost.setHeader("ENCTYPE", "multipart/form-data");
            // httpPost.setHeader("CharSet", HTTP.UTF_8);
            httpPost.setEntity(reqEntity);
            ret = executeHttpRequest(httpPost);
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
        return ret;
    }


    // ===================================================================
    // Methods for SubClass
    // ===================================================================

    // ===================================================================
    // Inner and Anonymous Classes
    // ===================================================================
}
